package gim_broker

import (
	"errors"
	"fmt"
	"net"
	"sync"
)

var (
	groups               []*Group // 群组集合
	groupsMutex          *sync.RWMutex
	idClientCache        map[string]*Client // 客户端id  客户端 映射容器
	idClientCacheMutex   *sync.RWMutex
	connClientCache      map[*net.TCPConn]*Client
	connClientCacheMutex *sync.RWMutex
)

func InitResource() {

	groupsMutex = new(sync.RWMutex)
	idClientCacheMutex = new(sync.RWMutex)
	idClientCache = make(map[string]*Client)
	connClientCacheMutex = new(sync.RWMutex)
	connClientCache = make(map[*net.TCPConn]*Client)
}

// Group 群组
type Group struct {
	Id      string   // 组编号
	Members []string // 成员id
	m       *sync.RWMutex
}

// ListGroups 获取所有群组
func ListGroups() []*Group {

	groupsMutex.RLock()
	defer groupsMutex.RUnlock()
	return groups
}

// AppendGroups 添加群组
func AppendGroups(group *Group) {

	groupsMutex.Lock()
	defer groupsMutex.Unlock()
	groups = append(groups, group)
}

func GetGroup(groupId string) *Group {
	groupsMutex.RLock()
	defer groupsMutex.RUnlock()
	for _, group := range groups {
		if group.Id == groupId {
			return group
		}
	}
	// 客户端请求加入的群组如果不存在，视为创建群组，
	g := &Group{Id: groupId, m: &sync.RWMutex{}}
	groups = append(groups, g)
	return g
}

// AddGroupMember 添加群组成员
func AddGroupMember(groupId, clientId string) error {

	group := GetGroup(groupId)
	if group == nil {
		return errors.New(fmt.Sprintf("group is nil groupId [%s]", groupId))
	}
	group.m.Lock()
	group.Members = append(group.Members, clientId)
	group.m.Unlock()
	return nil
}

// Client 终端
type Client struct {
	ClientId string // 客户端标识
	Ip       string // 客户端ip
	Conn     *net.TCPConn
	Groups   []*Group // 客户端加入的群组
}

// GetClientById 根据id获取终端
func GetClientById(id string) *Client {

	idClientCacheMutex.RLock()
	defer idClientCacheMutex.RUnlock()
	return idClientCache[id]
}

// GetClientByConn 根据连接获取终端
func GetClientByConn(conn *net.TCPConn) *Client {

	connClientCacheMutex.RLock()
	defer connClientCacheMutex.RUnlock()
	return connClientCache[conn]
}

// PutClient 存储终端
func PutClient(client *Client) error {

	if client.ClientId == "" {
		return errors.New("客户端id is nil")
	}
	idClientCacheMutex.Lock()
	idClientCache[client.ClientId] = client
	idClientCacheMutex.Unlock()

	connClientCacheMutex.Lock()
	connClientCache[client.Conn] = client
	connClientCacheMutex.Unlock()

	Logger.Infof("增加客户端 ClientId %s, ip %s", client.ClientId, client.Ip)
	return nil
}

func DeleteClientById(id string) {

	idClientCacheMutex.Lock()
	defer idClientCacheMutex.Unlock()
	if client, ok := idClientCache[id]; ok {
		delete(idClientCache, id)
		Logger.Infof("移除客户端 byId ClientId %s, ip %s", client.ClientId, client.Ip)
	}
}

func DeleteClientByConn(conn *net.TCPConn) {

	connClientCacheMutex.Lock()
	defer connClientCacheMutex.Unlock()
	if client, ok := connClientCache[conn]; ok {
		delete(connClientCache, conn)
		Logger.Infof("移除客户端 byConn ClientId %s, ip %s", client.ClientId, client.Ip)
	}
}
